﻿// EC800_Simu.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <direct.h>
#include <memory.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <process.h>
#include <Winsock2.h>
#include <assert.h>
#include <TCHAR.h>
#include <Windows.h>
#include "simu_800.h"
#include "ql_fs.h"

#define simu_imei "860061062461000"  // "860061062461372" // "860061060026425"
#define simu_imsi "460066632314352"
#define simu_iccid "89860622320009143521"
char* simu_iot_com = _T("\\\\.\\COM31");
//#define simu_iot_com "COM5"
#define simu_iot_com_baud 115200
#define simu_ip_addr 0x12345678
const int simu_base_station[6][5] = { {460,0,20935,230580263,-110}, {460, 1, 20750, 84684343, -84}, {460, 0, 20953, 230580264, -97}, {460, 11, 16475, 66286646, -103}, {460, 11, 16475, 66286646, -103}, {460, 11, 16475, 66286646, -103} };

// data call相关模拟功能 -----------------------------------------------------------------------------------------------
int ql_datacall_get_sim_profile_is_active(uint8_t nSim, int profile_idx)
{
	static int state = 0;
	int ret = state;
	state = 1;
	return ret;
}
int ql_network_register_wait(uint8_t nSim, unsigned int timeout_s)
{
	return 0;
}
int ql_set_data_call_asyn_mode(uint8_t nSim, int profile_idx, int enable)
{
	return 0;
}
int ql_start_data_call(uint8_t nSim, int profile_idx, int ip_version, char* apn_name, char* username, char* password, int auth_type)
{
	return 0;
}
int ql_stop_data_call(uint8_t nSim, int profile_idx)
{
	return 0;
}
int ql_get_data_call_info(uint8_t nSim, int profile_idx, ql_data_call_info_s* info)
{
	info->v4.addr.ip.addr = simu_ip_addr;
	return 0;
}
int ql_dev_get_modem_fun(uint8_t* func, uint8_t nSim)
{
	*func = 4;
	return 0;
}
// 系统相关模拟功能 -----------------------------------------------------------------------------------------------
// 时间系统功能
int ql_rtc_get_time(ql_rtc_time_t* ql_tm)
{
	time_t t = time(NULL);
	ql_rtc_time_t* tt = gmtime(&t);
	tt->tm_year += 1900;
	tt->tm_mon += 1;
	memcpy(ql_tm, tt, sizeof(ql_rtc_time_t));
	return 0;
}
int ql_rtc_get_localtime(ql_rtc_time_t* ql_tm)
{
	time_t t = time(NULL);
	ql_rtc_time_t* tt = localtime(&t);
	tt->tm_year += 1900;
	tt->tm_mon += 1;
	memcpy(ql_tm, tt, sizeof(ql_rtc_time_t));
	return 0;
}

ql_errcode_rtc_e ql_rtc_set_time(ql_rtc_time_t* tm) { return 0; }

ql_errcode_rtc_e ql_rtc_get_cfg(ql_rtc_cfg_t *ql_rtc_cfg)
{
	return 0;
}
ql_errcode_rtc_e ql_rtc_set_cfg(ql_rtc_cfg_t *ql_rtc_cfg)
{
	return 0;
}


void replace_substring(char* str, const char* old_substr, const char* new_substr) {
	char buffer[1024];
	char* p;

	if (!str || !old_substr || !new_substr)	return;

	p = strstr(str, old_substr);
	if (p) {
		strncpy(buffer, str, p - str);
		buffer[p - str] = '\0';
		strcat(buffer, new_substr);
		strcat(buffer, p + strlen(old_substr));
		strcpy(str, buffer);
	}
}

// 文件系统功能
QFILE ql_fopen(const char* file_name, const char* mode)
{
	char buf[1024];
	strcpy(buf, file_name);
	replace_substring(buf, "UFS:", ".");
	QFILE fp = fopen(buf, mode);
	if (fp == 0)
		return 0;
	else
		return fp;
}
int ql_fwrite(void* buffer, size_t size, size_t num, QFILE fd)
{
	return fwrite(buffer, size, num, fd);
}
int ql_fsize(QFILE fp)
{
	fseek(fp, 0, SEEK_END);
	int size = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	return size;
}
int ql_mkdir(const char* path, unsigned int mode)
{
	int ret = _mkdir((strchr(path, '/') + 1));
	if (ret == -1)
		ret = QL_DIR_DIR_ALREADY_EXIST;

	return ret;
}
int ql_remove(const char* file_name)
{
	char buf[1024];
	strcpy(buf, file_name);
	replace_substring(buf, "UFS:", ".");
	return remove(buf + 1);
}
int ql_fseek(QFILE fd, long offset, int origin)
{
	fseek(fd, offset, origin);
}
int ql_file_exist(const char* file_name)
{
	QFILE fp = ql_fopen(file_name, "r");
	if (fp <= 0) return -1;
	ql_fclose(fp);
	return 0;
}
int ql_fputs(const char* chr, QFILE fd)
{
	int ret = fputs(chr, fd);
	if (ret >= 0)
		return strlen(chr);
	else 
		return -1;
}
char* ql_fgets(char* str, int n, QFILE fd)
{
	return fgets(str, n, fd);
}
int ql_stat(const char* file_name, struct stat* st)
{
	char buf[1024];
	strcpy(buf, file_name);
	replace_substring(buf, "UFS:", ".");
	return stat(buf, st);
}
int ql_frewind(QFILE fd)
{
	rewind(fd);
	return 0;
}

// 多任务系统功能 -------------------------------------------------------------------------------------------
// simulate functions 最多支持32线程，每个线程队列深度16
simu_task_queue_t simu_task_queues[32] = { 0 };
QlOSStatus ql_rtos_event_send(ql_task_t	task_ref, ql_event_t* event)
{
	for (int i = 0; i < 32; i++) {
		if (simu_task_queues[i].taskRef == task_ref) {
			simu_task_queue_t* pq = simu_task_queues + i;
			ql_rtos_mutex_lock(pq->self_mutex, 100);
			// 满了，原版是取走第一条返回给用户供销毁回收内存，这里模拟系统，改为直接覆盖
			//if (simu_task_queues[i].cnt == 16) {  
			//	ret = simu_task_queues[i].buffs[pQueue->pos];
			//	if (++pQueue->pos == pQueue->max_cnt) pQueue->pos = 0;
			//	--pQueue->cnt;
			//}
			int new_pos = pq->pos + pq->cnt;
			if (new_pos >= 16) new_pos = new_pos - 16;
			memcpy(pq->buffs + new_pos, event, sizeof(ql_event_t));
			++pq->cnt;
			ql_rtos_mutex_unlock(pq->self_mutex);
			return 0;
		}
	}
	return -1;
}
QlOSStatus ql_event_wait(ql_event_t* event_strc, uint32_t timeout)
{
	pthread_t taskRef = pthread_self();
	for (int i = 0; i < 32; i++) {
		if (simu_task_queues[i].taskRef->p == taskRef.p) {
			simu_task_queue_t* pq = simu_task_queues + i;
			ql_rtos_mutex_lock(pq->self_mutex, 100);
			if (pq->cnt <= 0) {
				ql_rtos_mutex_unlock(pq->self_mutex);
				return -1;
			}
			memcpy(event_strc, pq->buffs+pq->pos, sizeof(ql_event_t));
			if (++pq->pos == 16) pq->pos = 0;
			--pq->cnt;
			ql_rtos_mutex_unlock(pq->self_mutex);
			return 0;
		}
	}
	return -1;
}

int ql_rtos_task_create(ql_task_t* taskRef, unsigned int stackSize, unsigned char priority, char* taskName, void (*taskStart)(void*), void* argv, unsigned int  event_count, ...)
{
	// 创建附属的消息队列
	for (int i = 0; i < 32; i++) {
		if (simu_task_queues[i].taskRef == NULL) {
			simu_task_queues[i].taskRef = malloc(sizeof(pthread_t));
			pthread_create(simu_task_queues[i].taskRef, NULL, (void* (*)(void*))taskStart, argv);
			//simu_task_queues[i].taskRef = taskRef;
			simu_task_queues[i].cnt = simu_task_queues[i].pos = 0;
			ql_rtos_mutex_create(&simu_task_queues[i].self_mutex);
			*taskRef = simu_task_queues[i].taskRef;
			return 0;
		}
	}
	return -1;
}
extern int ql_rtos_task_delete(ql_sem_t taskRef)
{
	return 0;
}

int ql_rtos_semaphore_create(ql_sem_t* semaRef, unsigned int initialCount)
{
	sem_init(semaRef, 0, initialCount);
	return 0;
}
int ql_rtos_semaphore_wait(ql_sem_t semaRef, unsigned int timeout)
{
	// TODO timeout no used
	sem_wait(&semaRef);
	return 0;
}
int ql_rtos_semaphore_release(ql_sem_t   semaRef)
{
	sem_post(&semaRef);
	return 0;
}
int ql_rtos_semaphore_delete(ql_sem_t   semaRef)
{
	sem_destroy(&semaRef);
	return 0;
}
QlOSStatus ql_rtos_mutex_create(ql_mutex_t *mutexRef)
{
	return pthread_mutex_init(mutexRef, NULL);
}
QlOSStatus ql_rtos_mutex_lock(ql_mutex_t mutexRef, uint32_t timeout)
{
	struct timespec tm;
	tm.tv_sec = 0;
	tm.tv_nsec = timeout * 1000 * 1000;
	return pthread_mutex_timedlock(&mutexRef, &tm);
}
// QlOSStatus ql_rtos_mutex_try_lock(ql_mutex_t mutexRef);
QlOSStatus ql_rtos_mutex_unlock(ql_mutex_t mutexRef)
{
	return pthread_mutex_unlock(&mutexRef);
}
QlOSStatus ql_rtos_mutex_delete(ql_mutex_t mutexRef)
{
	return pthread_mutex_destroy(&mutexRef);
}

int ql_power_reset(int reset_mode)
{
	printf("simulator halt: call ql_power_reset");
	while (1);
}
void ql_rtos_task_sleep_ms(unsigned int ms)
{
	if(ms >= 15)
		Sleep(ms);
	else
		for (int i = 0; i < ms * 1000 * 1000; i++);
}
void ql_rtos_task_sleep_s(unsigned int s)
{
	Sleep(s * 1000);
}
// fota系统功能
ql_errcode_fota_e ql_fota_get_result(ql_fota_result_e* p_fota_result)
{
	return QL_FOTA_SUCCESS;
}
ql_errcode_fota_e ql_fota_file_reset(int del_image)
{
	return QL_FOTA_SUCCESS;
}
ql_errcode_fota_e ql_fota_image_verify(char* PackFileName)
{
	return QL_FOTA_SUCCESS;
}
// 杂项系统功能
int ql_dev_get_imei(char* p_imei, size_t imei_len, uint8_t nSim)
{
	//strcpy(p_imei, "860061062583803");
	strcpy(p_imei, simu_imei);
	return 0;
}
int ql_sim_get_imsi(uint8_t nSim, char* imsi, size_t imsi_len)
{
	// TODO TBD
	//strcpy(imsi, "860061062583803");
	strcpy(imsi, simu_imsi);
	return 0;
}
int ql_sim_get_iccid(uint8_t nSim, char* iccid, size_t iccid_len)
{
	// TODO TBD
	//strcpy(iccid, "00860061062461372");
	strcpy(iccid, simu_iccid);
	return 0;
}
int ql_nw_get_csq(uint8_t nSim, unsigned char* csq)
{
	// TODO TBD
	*csq = 25;
	return 0;
}

// HTTP相关模拟功能 -----------------------------------------------------------------------------------------------
typedef struct {
	http_client_t* client;
	http_client_event_cb_t http_event_func;
	http_client_write_data_cb_t http_write_func;
	void* http_write_func_arg;
} SimuHttpHandle;
SimuHttpHandle simu_http_handles[10] = { 0 };
static SimuHttpHandle * GetSimuHttpHandle(http_client_t* client)
{
	for (int i = 0; i < 10; i++)
		if (simu_http_handles[i].client == client) return &(simu_http_handles[i]);
	return NULL;
}
//http_client_event_cb_t http_event_func = NULL;
//http_client_write_data_cb_t http_write_func = NULL;
//void* http_write_func_arg = NULL;
int  ql_httpc_new(http_client_t* client, http_client_event_cb_t cb, void* arg)
{
	SimuHttpHandle* handle = GetSimuHttpHandle(NULL);
	*client = ghttp_request_new();
	handle->client = client;
	handle->http_event_func = cb;
	//ghttp_set_sync(*client, ghttp_async);
	handle->http_write_func = NULL;
	handle->http_write_func_arg = NULL;
	return 0;
}
int  ql_httpc_setopt(http_client_t* client, int opt_tag, ...)
{
	va_list ptr;
	va_start(ptr, opt_tag);

	switch (opt_tag)
	{
		case HTTP_CLIENT_OPT_METHOD:
		{
			http_method_e type = va_arg(ptr, http_method_e);
			if(type == HTTP_METHOD_GET)
				ghttp_set_type(*client, ghttp_type_get);
			else if(type == HTTP_METHOD_POST)
				ghttp_set_type(*client, ghttp_type_post);
			break;
		}
		case HTTP_CLIENT_OPT_REQUEST_HEADER:
		{
			char *p = va_arg(ptr, char *);
			ghttp_set_header(*client, "Content-Type", p);
			break;
		}
		case HTTP_CLIENT_OPT_WRITE_DATA:
		{
			SimuHttpHandle* handle = GetSimuHttpHandle(client);
			handle->http_write_func_arg = va_arg(ptr, void*);
			//http_write_func_arg = va_arg(ptr, void*);
			break;
		}
		case HTTP_CLIENT_OPT_WRITE_FUNC:
		{
			SimuHttpHandle* handle = GetSimuHttpHandle(client);
			handle->http_write_func = va_arg(ptr, http_client_write_data_cb_t);
			break;
		}
		case HTTP_CLIENT_OPT_URL:
		{
			char* p = va_arg(ptr, char*);
			ghttp_set_uri(*client, p);
			break;
		}
		default: break;
	}
	va_end(ptr);
	return 0;
}
int  ql_httpc_getinfo(http_client_t* client, int info, ...)
{
	va_list ptr;
	va_start(ptr, info);

	switch (info)
	{
	case HTTP_INFO_RESPONSE_CODE:
	case HTTP_INFO_CHUNK_ENCODE:
	{
		int * ret = va_arg(ptr, int *);
		*ret = 0;
		break;
	}
	case HTTP_INFO_CONTENT_LEN:
	{
		int* ret = va_arg(ptr, int*);
		*ret = ghttp_get_body_len(*client);
		break;
	}
	}
	va_end(ptr);
	return 0;

}
static void http_perform_func(void *arg)
{
	http_client_t* client = (http_client_t*)arg;
	SimuHttpHandle* handle = GetSimuHttpHandle(client);

	handle->http_event_func(client, HTTP_EVENT_SESSION_ESTABLISH, 0, NULL);
	ghttp_status status = ghttp_process(*client);
	int len = ghttp_get_body_len(*client);
	unsigned char* buf = ghttp_get_body(*client);
	handle->http_event_func(client, HTTP_EVENT_RESPONE_STATE_LINE, 0, NULL);
	handle->http_write_func(client, handle->http_write_func_arg, buf, len, 0);
	handle->http_event_func(client, HTTP_EVENT_SESSION_DISCONNECT, 0, NULL);
	//ghttp_clean(*client);
	return;
}
int  ql_httpc_perform(http_client_t* client)
{
	ghttp_prepare(*client);
	pthread_t pt;
	pthread_create(&pt, NULL, http_perform_func, client);
	return 0;
}
extern int  ql_httpc_release(http_client_t* client)
{
	ghttp_clean(*client);
	ghttp_request_destroy(*client);
	return 0;
}


// WIFI相关模拟功能 -----------------------------------------------------------------------------------------------
#include <wlanapi.h>
#pragma comment(lib, "wlanapi.lib")
static BOOL wifi_scan_bWait = TRUE;
static int wifi_scan_cnt = 0;
void WlanNotificationCallback(PWLAN_NOTIFICATION_DATA NotifData, PVOID Arg2) 
{
    if (NotifData == NULL || NotifData->NotificationSource != WLAN_NOTIFICATION_SOURCE_ACM) return;

    if (NotifData->NotificationCode == wlan_notification_acm_scan_complete) wifi_scan_bWait = TRUE;
	else if (NotifData->NotificationCode == wlan_notification_acm_scan_fail) wifi_scan_bWait = FALSE;
	else wifi_scan_bWait = FALSE;
}
ql_errcode_wifi_scan_e ql_wifiscan_do(uint16_t *p_ap_cnt, ql_wifi_ap_info_s *p_ap_infos)
{
	char NicDesc[256];
	uint32_t dwCurVersion = 0;
	HANDLE hClient = NULL;
	PWLAN_INTERFACE_INFO_LIST pInterfaceList;
	GUID guid;
	
	if(ERROR_SUCCESS != WlanOpenHandle(2, NULL, &dwCurVersion, &hClient)) {
		SimuLog("wifi open error !");
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	if(ERROR_SUCCESS != WlanEnumInterfaces(hClient, NULL, &pInterfaceList)) {
		SimuLog("enum interface error !");
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	wcstombs(NicDesc, pInterfaceList->InterfaceInfo[0].strInterfaceDescription, sizeof(NicDesc));
	SimuLog("Device_Name=%s", NicDesc);
	guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;
	//  || pInterfaceList->InterfaceInfo[0].isState == wlan_interface_state_disconnected
	if (pInterfaceList->InterfaceInfo[0].isState == wlan_interface_state_not_ready) {
		SimuLog("wifi %s is not ready", NicDesc);
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	// register callback func
	uint32_t dwNotifSourcePre;
	if(ERROR_SUCCESS != WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ACM, TRUE, (WLAN_NOTIFICATION_CALLBACK)WlanNotificationCallback, NULL, NULL, &dwNotifSourcePre)) {
		SimuLog("wifi register callback error !");
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	if (ERROR_SUCCESS != WlanScan(hClient, &guid, NULL, NULL,NULL)){
		SimuLog("wifi scan error !");
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	SimuLog("Waiting for scan complete ... ");
	while (wifi_scan_bWait) Sleep(500);
	wifi_scan_bWait = TRUE;
	// unregister callback func
	WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ACM, TRUE, NULL, NULL, NULL, &dwNotifSourcePre);

	PWLAN_AVAILABLE_NETWORK_LIST pWlanList = (WLAN_AVAILABLE_NETWORK_LIST *)WlanAllocateMemory(sizeof(WLAN_AVAILABLE_NETWORK_LIST));
	// WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES | WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES,
	if (ERROR_SUCCESS != WlanGetAvailableNetworkList(hClient, &guid, 0, NULL, &pWlanList)){
		WlanFreeMemory(pWlanList);
		SimuLog("wifi scan get list error !");
		return QL_WIFISCAN_EXECUTE_ERR;
	}
	*p_ap_cnt = (wifi_scan_cnt > pWlanList->dwNumberOfItems) ? pWlanList->dwNumberOfItems : wifi_scan_cnt;
	for(int i = 0; i < *p_ap_cnt; i++) {
		// SimuLog("find wifi ap ssid: %s, quality: %3d", pWlanList->Network[i].dot11Ssid.ucSSID, pWlanList->Network[i].wlanSignalQuality);
		PWLAN_BSS_LIST pBssList;
		// get bssid(mac) and lrssi
		WlanGetNetworkBssList(hClient, &guid, &(pWlanList->Network[i].dot11Ssid), pWlanList->Network[i].dot11BssType, pWlanList->Network[i].bSecurityEnabled, NULL, &pBssList);
		p_ap_infos[i].bssid_low = (pBssList->wlanBssEntries[0].dot11Bssid[2] << 24) + (pBssList->wlanBssEntries[0].dot11Bssid[3] << 16) + (pBssList->wlanBssEntries[0].dot11Bssid[4] << 8) + pBssList->wlanBssEntries[0].dot11Bssid[5];
		p_ap_infos[i].bssid_high = (pBssList->wlanBssEntries[0].dot11Bssid[0] << 8) + pBssList->wlanBssEntries[0].dot11Bssid[1];
		p_ap_infos[i].rssival = pBssList->wlanBssEntries[0].lRssi;
		strncpy(p_ap_infos[i].ssid, pWlanList->Network[i].dot11Ssid.ucSSID, sizeof(p_ap_infos[i].ssid));
	}
	
	WlanCloseHandle(hClient, NULL);
	WlanFreeMemory(pWlanList);
	return 0;
}
ql_errcode_wifi_scan_e ql_wifiscan_option_set(uint16_t expect_ap_cnt, uint8_t round, uint16_t scan_channel, uint32_t channel_time)
{
	wifi_scan_cnt = expect_ap_cnt;
	return 0;
}
ql_errcode_wifi_scan_e ql_wifiscan_open(void)
{
	return 0;
}
ql_errcode_wifi_scan_e ql_wifiscan_close(void)
{
	return 0;
}
ql_nw_errcode_e ql_nw_get_cell_info(uint8_t nSim, ql_nw_cell_info_s *cell_info)
{
	// TODO get some true data to simulate
	cell_info->gsm_info_valid = 0;
	cell_info->gsm_info_num = 0;
	cell_info->lte_info_valid = 1;
	cell_info->lte_info_num = 6;
	cell_info->lte_info[0].flag = 0;
	cell_info->lte_info[1].flag = 1;
	cell_info->lte_info[2].flag = 1;
	cell_info->lte_info[3].flag = 1;
	cell_info->lte_info[4].flag = 1;
	cell_info->lte_info[5].flag = 1;
	for (int i = 0; i < 6; i++) {
		cell_info->lte_info[i].mcc = simu_base_station[i][0];
		cell_info->lte_info[i].mnc = simu_base_station[i][1];
		cell_info->lte_info[i].tac = simu_base_station[i][2];
		cell_info->lte_info[i].cid = simu_base_station[i][3];
		cell_info->lte_info[i].rssi = simu_base_station[i][4];
	}
	return 0;
}

#define UART_BUF_SIZE 2048

static char uart_ports[16][32] = {0};
static HANDLE uart_handles[16] = { 0 };
static HANDLE pipe_read[16] = { 0 };
static HANDLE pipe_write[16] = { 0 };
static ql_uart_config_s uart_configs[16] = { 0 };
static ql_uart_callback uart_callbacks[16] = { 0 };
static unsigned char uart_read_buff[16][UART_BUF_SIZE];
static unsigned int uart_read_len[16] = {0};


static void uart_thread_func(void* arg)
{
	while (1) {
		for (int i = 0; i < 16; i++) {
			HANDLE h = (uart_handles[i]) ? uart_handles[i] : pipe_read[i]; // 使用串口还是管道模拟
			if (h == 0 || uart_callbacks[i] == NULL) continue;
			unsigned char *buf = uart_read_buff[i];
			unsigned int* len = uart_read_len + i;
			ql_uart_callback uart_cb = uart_callbacks[i];
			if (h != 0) {
				int b = ReadFile(h, buf, UART_BUF_SIZE, len, NULL);
				if (*len > 0) {
					uart_cb(QUEC_UART_RX_RECV_DATA_IND, i, *len);
				}
				else {
					int x = GetLastError();
				}
			}
		}
	}
	return;
}
int ql_uart_open(ql_uart_port_number_e port)
{
	DCB dcb;
	COMMTIMEOUTS CommTimeouts;
	static pthread_t *puart_thread = NULL;
	static pthread_t uart_thread;
	if (port < 0 || port >= 16) return 1;

	// 启动接受线程
	if (puart_thread == NULL) {
		//pthread_create(&uart_thread, NULL, uart_thread_func, NULL);
		//puart_thread = &uart_thread;
		puart_thread = _beginthread(uart_thread_func, 0, 0);
	}
	// 使用匿名管道模拟
	if (pipe_read[port] != 0) {
		// 启动模拟接受线程
		//simu_uart->rx_thread = _beginthread(SimuUartThreadFunc, 0, simu_uart);
		//assert(INVALID_HANDLE_VALUE != simu_uart->rx_thread);
		return;
	}

	//打开串口
	int wcom_port_len = strlen(uart_ports[port]) + 1;
	assert(wcom_port_len < 32);
	wchar_t wcom_port[32] = { 0 };
	mbstowcs(wcom_port, uart_ports[port], wcom_port_len);
	uart_handles[port] = CreateFile(wcom_port,    //串口名称
		GENERIC_READ | GENERIC_WRITE,			//可读、可写   				 
		0,            // No Sharing                               
		NULL,         // No Security                              
		OPEN_EXISTING,// Open existing port only                     
		FILE_ATTRIBUTE_NORMAL,            // Non Overlapped I/O                           
		NULL);        // Null for Comm Devices
	if (INVALID_HANDLE_VALUE == uart_handles[port]) {
		DWORD err = GetLastError();
		return 1;
	}
	// 设置读写缓存大小
	if (!SetupComm(uart_handles[port], UART_BUF_SIZE, UART_BUF_SIZE)) {
		return 1;
	}
	//设定读写超时
	CommTimeouts.ReadIntervalTimeout = 1;//读间隔超时
	//CommTimeouts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
	CommTimeouts.ReadTotalTimeoutMultiplier = 0;//读时间系数
	CommTimeouts.ReadTotalTimeoutConstant = 100;//读时间常量
	CommTimeouts.WriteTotalTimeoutMultiplier = 1;//写时间系数
	CommTimeouts.WriteTotalTimeoutConstant = 1;//写时间常量
	if (!SetCommTimeouts(uart_handles[port], &CommTimeouts)) { //设置超时
		return 1;
	}
	//设置串口状态属性
	GetCommState(uart_handles[port], &dcb);//获取当前
	dcb.BaudRate = uart_configs[port].baudrate; //波特率
	dcb.ByteSize = uart_configs[port].data_bit; //每个字节有位数
	dcb.Parity = uart_configs[port].parity_bit; //无奇偶校验位
	dcb.StopBits = uart_configs[port].stop_bit; //一个停止位
	if (!SetCommState(uart_handles[port], &dcb)) {
		return 1;
	}
	return 0;
}
int ql_uart_set_dcbconfig(ql_uart_port_number_e port, ql_uart_config_s* dcb)
{
	if (port < 0 || port > 16) return 1;
	memcpy(&uart_configs[port], dcb, sizeof(ql_uart_config_s));
	return 0;
}
int ql_uart_register_cb(ql_uart_port_number_e port, ql_uart_callback uart_cb)
{
	uart_callbacks[port] = uart_cb;
	return 0;
}
int ql_uart_write(ql_uart_port_number_e port, unsigned char* data, unsigned int data_len)
{
	unsigned int ret = 0;
	if(uart_handles[port] != 0)
		WriteFile(uart_handles[port], data, data_len, &ret, NULL);
	else
		WriteFile(pipe_write[port], data, data_len, &ret, NULL);
	DWORD x = GetLastError();
	return ret;
}
int ql_uart_read(ql_uart_port_number_e port, unsigned char* data, unsigned int data_len)
{
	if (data_len > uart_read_len[port]) data_len = uart_read_len[port];
	memcpy(data, uart_read_buff[port], data_len);
	return data_len;
}
#include "ql_ntp_client.h"
ntp_client_id ql_ntp_sync(const char* host, ql_ntp_sync_option* user_option, ql_ntp_sync_result_cb cb, void* arg, int* error_code)
{
	ntp_client_id cli_id = 1;
	time_t timer = time(NULL);
	struct tm *sync_time = localtime(&timer);
	cb(cli_id, QL_NTP_SUCCESS, sync_time, NULL);
	return 1;
}

// mqtt相关模拟功能 -----------------------------------------------------------------------------------------------

mqtt_client_t* simu_client;

static int open_nb_socket(const char* addr, const char* port) {
	struct addrinfo hints = { 0 };

	hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
	hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
	int sockfd = -1;
	int rv;
	struct addrinfo* p, * servinfo;

	/* get address information */
	rv = getaddrinfo(addr, port, &hints, &servinfo);
	if (rv != 0) {
		fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv));
		return -1;
	}

	/* open the first possible socket */
	for (p = servinfo; p != NULL; p = p->ai_next) {
		sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
		if (sockfd == -1) continue;

		/* connect to server */
		rv = connect(sockfd, p->ai_addr, p->ai_addrlen);
		if (rv == -1) {
			close(sockfd);
			sockfd = -1;
			continue;
		}
		break;
	}

	/* free servinfo */
	freeaddrinfo(servinfo);

	/* make non-blocking */
#if !defined(_WIN32)
	if (sockfd != -1) fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
#else
	if (sockfd != INVALID_SOCKET) {
		int iMode = 1;
		ioctlsocket(sockfd, FIONBIO, &iMode);
	}
#endif
#if defined(__VMS)
	/*
		OpenVMS only partially implements fcntl. It works on file descriptors
		but silently fails on socket descriptors. So we need to fall back on
		to the older ioctl system to set non-blocking IO
	*/
	int on = 1;
	if (sockfd != -1) ioctl(sockfd, FIONBIO, &on);
#endif

	/* return the new socket fd */
	return sockfd;
}

int ql_bind_sim_and_profile(uint8_t nSim, int profile_idx, uint16_t* sim_cid)
{
	return 0;
}
int ql_mqtt_client_init(mqtt_client_t* client, int cid)
{
	//client = malloc(sizeof(mqtt_client_t));
	//memset(client, 0, sizeof(mqtt_client_t));
	simu_client = client;
}
void simu_mqtt_callback(void** unused, struct mqtt_response_publish* published)
{
	/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
	char* topic_name = (char*)malloc(published->topic_name_size + 1);
	memcpy(topic_name, published->topic_name, published->topic_name_size);
	topic_name[published->topic_name_size] = '\0';

	simu_client->inpub_cb(simu_client, NULL, 0, topic_name, published->application_message, published->application_message_size);
	//printf("Received publish('%s'): %s\n", topic_name, (const char*)published->application_message);

	free(topic_name);
}
void* simu_mqtt_client_refresher(void* client)
{
	while (1)
	{
		mqtt_sync(&((mqtt_client_t*)client)->client);
		Sleep(100);
	}
	return NULL;
}

// connect function
typedef struct {
	mqtt_client_t* client;
	const char* host;
	mqtt_connection_cb_t cb;
	void* arg;
	const struct mqtt_connect_client_info_t* client_info;
} simu_mqtt_connect;
static void* simu_ql_mqtt_connect(void *param)
{
	simu_mqtt_connect* conn = (simu_mqtt_connect*)param;
	char* p = strrchr(conn->host, ':');
	if (p == NULL) {
		free(conn);
		conn->cb(conn->client, NULL, 1);
		return NULL;
	}
	char addr[256];
	char port[16];
	strncpy(addr, conn->host, p - conn->host);
	addr[p - conn->host] = 0;
	strcpy(port, p + 1);
	mqtt_client_t* client = conn->client;
	/* open the non-blocking TCP socket (connecting to the broker) */
	client->sockfd = open_nb_socket(addr, port);
	if (client->sockfd == -1) {
		conn->cb(client, NULL, 1);
		free(conn);
		return NULL;
	}
	/* setup a client */
	mqtt_init(&(client->client), client->sockfd, client->sendbuf, sizeof(client->sendbuf), 
		client->recvbuf, sizeof(client->recvbuf), simu_mqtt_callback);
	/* Ensure we have a clean session */
	uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
	/* Send connection request to the broker. */
	struct mqtt_connect_client_info_t* client_info = conn->client_info;
	mqtt_connect(&(client->client), client_info->client_id, client_info->will_topic, client_info->will_msg,
		0, client_info->client_user, client_info->client_pass, connect_flags, client_info->keep_alive);
	/* check that we don't have any errors */
	if (client->client.error != MQTT_OK)
		conn->cb(conn->client, NULL, 1);
	else
		conn->cb(conn->client, NULL, 0);
	free(conn);

	// 建立接受线程
	pthread_create(&client->tid, NULL, simu_mqtt_client_refresher, client);

	return NULL;
}
int ql_mqtt_connect(mqtt_client_t* client, const char* host, mqtt_connection_cb_t cb, void* arg, const struct mqtt_connect_client_info_t* client_info, mqtt_state_exception_cb_t exp_cb)
{
	simu_mqtt_connect *conn = malloc(sizeof(simu_mqtt_connect));
	conn->client = client;
	if(strlen(host) > 7 && host[4] == ':' && host[5] == '/') // remove "mqtt://" in pc platform
		conn->host = host + 7;
	else 
		conn->host = host;
	conn->cb = cb;
	conn->client_info = client_info;
	conn->client->exp_cb = exp_cb;
	// 开线程启动连接
	pthread_t tid;
	pthread_create(&tid, NULL, simu_ql_mqtt_connect, conn);
	return MQTTCLIENT_WOUNDBLOCK;
}
// subscribe function
typedef struct {
	mqtt_client_t* client;
	const char* topic;
	unsigned char qos;
	mqtt_request_cb_t cb;
	void* arg;
	unsigned char sub;
} simu_mqtt_sub;
static void* simu_ql_mqtt_sub_unsub(void* param)
{
	simu_mqtt_sub* sub = (simu_mqtt_sub*)param;
	if (sub->sub)
		/* subscribe */
		mqtt_subscribe(&(sub->client->client), sub->topic, sub->qos);
	else 
		mqtt_unsubscribe(&(sub->client->client), sub->topic);

	if (sub->client->client.error == MQTT_OK)
		sub->cb(sub->client, NULL, 0);
	else
		sub->cb(sub->client, NULL, 1);
	free(sub);
	return NULL;
}
int ql_mqtt_sub_unsub(mqtt_client_t* client, const char* topic, unsigned char qos, mqtt_request_cb_t cb, void* arg, unsigned char sub)
{
	simu_mqtt_sub *subs = malloc(sizeof(simu_mqtt_sub));
	subs->client = client;
	subs->topic = topic;
	subs->qos = qos;
	subs->cb = cb;
	subs->arg = arg;
	subs->sub = sub;
	pthread_t tid;
	pthread_create(&tid, NULL, simu_ql_mqtt_sub_unsub, subs);
	return MQTTCLIENT_WOUNDBLOCK;
}
int ql_mqtt_set_inpub_callback(mqtt_client_t* client, mqtt_incoming_publish_cb_t inpub_cb, void* arg)
{
	client->inpub_cb = inpub_cb;
	return 0;
}
// publish function
typedef struct {
	mqtt_client_t* client;
	const char* topic;
	const void* payload;
	unsigned short payload_length;
	unsigned char qos;
	unsigned char retain;
	mqtt_request_cb_t cb;
	void* arg;
} simu_mqtt_pub;
static void* simu_ql_mqtt_publish(void* param)
{
	simu_mqtt_pub *pub = (simu_mqtt_pub *)param;
	/* publish the time */
	mqtt_publish(&(pub->client->client), pub->topic, pub->payload, pub->payload_length, pub->qos);
	if (pub->client->client.error == MQTT_OK)
		pub->cb(pub->client, NULL, 0);
	else
		pub->cb(pub->client, NULL, 1);
	free(pub);
	return NULL;
}
int ql_mqtt_publish(mqtt_client_t* client, const char* topic, const void* payload, unsigned short payload_length, unsigned char qos, unsigned char retain, mqtt_request_cb_t cb, void* arg)
{
	simu_mqtt_pub *pub = malloc(sizeof(simu_mqtt_pub));
	pub->client = client;
	pub->topic = topic;
	pub->payload = payload;
	pub->payload_length = payload_length;
	pub->qos = qos;
	pub->cb = cb;
	pub->arg = arg;
	pthread_t tid;
	pthread_create(&tid, NULL, simu_ql_mqtt_publish, pub);
	return MQTTCLIENT_WOUNDBLOCK;
}

int ql_mqtt_disconnect(mqtt_client_t* client, mqtt_disconnect_cb_t cb, void* arg)
{
	mqtt_disconnect(&client->client);
	cb(client, NULL, 0);
}
QlOSStatus ql_gettimeofday(ql_timeval_t* timeval)
{
	clock_t tm = clock();
	timeval->sec = tm / 1000;
	timeval->usec = tm % 1000;

}

// BLE(8910) related  ------------------------------------------------------------------------------------------------
ql_errcode_bt_e ql_bt_ble_get_nv_addr(ql_bt_addr_s* mac_addr)
{
	mac_addr->addr[0] = 0xe8;
	mac_addr->addr[1] = 0x8d;
	mac_addr->addr[2] = 0xa6;
	mac_addr->addr[3] = 0x89;
	mac_addr->addr[4] = 0xec;
	mac_addr->addr[5] = 0xb0;
	return 0;
}
ql_errcode_bt_e ql_ble_gatt_server_init(ql_bt_callback bt_cb) { return 0; }
ql_errcode_bt_e ql_bt_start() { return 0; }
ql_errcode_bt_e ql_bt_ble_set_localname(ql_bt_ble_local_name_s local_name) { return 0; }
ql_errcode_bt_e ql_bleadv_set_param(ql_bleadv_param_s adv_param) { return 0; }
ql_errcode_bt_e ql_bleadv_set_data(ql_bleadv_set_data_s avd_data) { return 0; }
ql_errcode_bt_e ql_bleadv_start() { return 0; }
ql_errcode_bt_e ql_bt_stop() { return 0; }
ql_errcode_bt_e ql_ble_gatt_server_release() { return 0; }


int ql_gpio_init(ql_GpioNum gpio_num, ql_GpioDir gpio_dir, ql_PullMode gpio_pull, ql_LvlMode gpio_lvl) { return 0; }
int ql_pin_set_func(uint8_t pin_num, uint8_t func_sel) { return 0; }
int ql_gpio_set_level(ql_GpioNum gpio_num, ql_LvlMode gpio_lvl) { return 0; }
int ql_dev_feed_wdt(void) { return 0; }
int ql_dev_get_firmware_version(char* p_version, size_t version_len) { return 0; }
ql_errcode_wifi_scan_e ql_wifiscan_register_cb(void* wifiscan_cb) { return 0; }
void ql_wifiscan_async_start(void) {}
ql_errcode_wifi_scan_e ql_wifiscan_async(void) { return 0; }
QlOSStatus ql_event_try_wait(ql_event_t* event_strc) {return 0;}

// 模拟windows没有的strnstr
char* strnstr(char* org, char *target, int len)
{
	char tmp[4096+4];
	if (len >= 4096) return NULL;
	memcpy(tmp, org, len);
	tmp[len] = 0;
	char *p = strstr(tmp, target);
	if (p == NULL) return p;
	return (p - tmp + org);
}
// 模拟打印log时输出时间
const char* GetLocalTimeStrWin32(void)
{
	static char buf[24];
	time_t t = time(NULL);
	struct tm* tt = localtime(&t);
	tt->tm_year += 1900;
	tt->tm_mon += 1;
	int ms = t % 1000;
	sprintf(buf, "%04d/%02d/%02d-%02d:%02d:%02d:%03d", tt->tm_year, tt->tm_mon, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec, ms);
	return buf;
}

// 1. 把EC800的相关代码移到EC800_Simu下，自成一个目录比如itc_zy1这样，对照修改task.json加入这个部分编译
// 修改如下部分 -----------------------------------------------------------------------------------------------
// 引入每个任务句柄，供模拟器模拟多任务并行。
extern ql_task_t zq_iot_task;
extern ql_task_t wifiscan_task;
extern ql_task_t basescan_task;
// 声明EC800主要入口函数，一般一个，也可以多个
extern void zq_app_init(void);


//#pragma comment(linker, "/SUBSYSTEM:CONSOLE /ENTRY:wmainCRTStartup")
// 主函数 cat1.exe "串口1" "串口2"
// 控制台运行例子：cat1.exe "\\\\.\\COM31" "NULL"
int main(int argc, char* argv[])
{
	// 设置本地化，以支持多字节字符集
	setlocale(LC_ALL, "");

	if (argc < 2) return;
	if (argv[1][0] == '\\' || argv[1][0] == 'c' || argv[1][0] == 'C')  // 串口
		strcpy(uart_ports[QL_UART_PORT_1], argv[1]);
	else if (argv[1][0] >= 0x30 && argv[1][0] <= 0x39) { // 数字，匿名管道
		char* write_str = strchr(argv[1], '+');
		assert(write_str);
		*write_str = '\0';
		pipe_read[QL_UART_PORT_1] = (void*)atoi(argv[1]);
		pipe_write[QL_UART_PORT_1] = (void*)atoi(write_str + 1);
	}
	else
		assert(false);

	// 初始化windows套接字
	WSADATA WsaData;
	WSAStartup(MAKEWORD(2, 2), &WsaData);

	// 延时1500ms，模拟cat1操作系统启动时间
	Sleep(1500);
	// 调用EC800主要入口函数，可以多个
	zq_app_init();	
	if (zq_iot_task) {
		pthread_join(*zq_iot_task, NULL); // 任务模拟
		pthread_join(*wifiscan_task, NULL); // 任务模拟
		pthread_join(*basescan_task, NULL); // 任务模拟
	}

	// 清除windows套接字
	WSACleanup();
}
//void ThreadMain(void)
//{
//	WSADATA WsaData;
//	WSAStartup(MAKEWORD(2, 2), &WsaData);
//	simulator_init(); // simulator初始化
//
//	simu_test1();
//
//	zq_app_init();	// 调用EC800主要入口函数，可以多个
//	pthread_join(*zq_iot_task, NULL); // 任务模拟
//	pthread_join(*wifiscan_task, NULL); // 任务模拟
//	pthread_join(*basescan_task, NULL); // 任务模拟
//	WSACleanup();
//
//}
//
//int main_close()
//{
//}
//HANDLE simu_main_h;
//__declspec(dllexport) void Cat1Switch(int isOn);
//void Cat1Switch(int isOn)
//{
//	if (isOn) {
//		//main();
//		simu_main_h = _beginthread(ThreadMain, 0, NULL);
//	}
//	else {
//		if (simu_main_h) {
//			TerminateThread(simu_main_h, 0);
//			CloseHandle(simu_main_h);
//		}
//	}
//}

#pragma comment(lib, "winmm.lib")
static void (*simu_timer_cb)(void *);
void CALLBACK timer_handler(UINT uTimerID, UINT uMsg, UINT_PTR dwUser, UINT_PTR dw1, UINT_PTR dw2)
{
	simu_timer_cb(NULL);
}
// simulate timer function, current only support interrupt mode and only support 1 instance
QlOSStatus ql_rtos_timer_create(ql_timer_t* timerRef, ql_task_t taskRef, void (*callBackRoutine)(void*), void* timerArgc) 
{
	simu_timer_cb = callBackRoutine;
	timeBeginPeriod(1);
	return 0;
}
QlOSStatus ql_rtos_timer_start(ql_timer_t timerRef, uint32_t set_Time, unsigned char cyclicalEn)
{
	uint32_t mTimerId = timeSetEvent(set_Time, 0, timer_handler, 0, TIME_PERIODIC);
	return 0;
}


// 开发中的一些测试功能 -----------------------------------------------------------------------------------------------



void exit_example(int status, int sockfd, pthread_t* client_daemon)
{
	if (sockfd != -1) close(sockfd);
	if (client_daemon != NULL) pthread_cancel(*client_daemon);
	exit(status);
}


